package org.budo.launcher.netty.servlet;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.jsp.JspFactory;

import org.apache.jasper.runtime.JspFactoryImpl;
import org.budo.launcher.service.AbstractBudoLauncherService;
import org.budo.launcher.service.util.LauncherUtil;
import org.budo.netty.servlet.server.DefaultBudoServletServer;
import org.budo.netty.servlet.server.connector.Connector;
import org.budo.netty.servlet.server.connector.netty.NettyConnector;
import org.budo.netty.servlet.server.exception.handler.DefaultExceptionHandler;
import org.budo.netty.servlet.server.exception.handler.ExceptionHandler;
import org.budo.netty.servlet.server.resource.loader.BudoFileResourceLoader;
import org.budo.netty.servlet.server.resource.loader.ResourceLoader;
import org.budo.netty.servlet.server.session.repository.MapSessionRepository;
import org.budo.netty.servlet.server.session.repository.SessionRepository;
import org.budo.xml.Xml;
import org.budo.xml.XmlObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author lmw
 */
public class BudoNettyServletLauncher extends AbstractBudoLauncherService {
    private static final Logger log = LoggerFactory.getLogger(BudoNettyServletLauncher.class);

    @Override
    public void run(String[] args) {
        ResourceLoader resourceLoader = this.resourceLoader();
        SessionRepository sessionRepository = new MapSessionRepository();
        ExceptionHandler exceptionHandler = new DefaultExceptionHandler();
        Connector connector = new NettyConnector(this.getLauncherPort());

        DefaultBudoServletServer budoNettyServletServer = new DefaultBudoServletServer();
        budoNettyServletServer.setConnector(connector);
        budoNettyServletServer.setExceptionHandler(exceptionHandler);
        budoNettyServletServer.setSessionRepository(sessionRepository);
        budoNettyServletServer.setResourceLoader(resourceLoader);

        this.parseWebXml(budoNettyServletServer);

        this.addJspServlet(budoNettyServletServer);

        log.info("#19 budoNettyServletServer=" + budoNettyServletServer);
        budoNettyServletServer.start();
    }

    private void addJspServlet(DefaultBudoServletServer budoNettyServletServer) {
        if (JspFactory.getDefaultFactory() == null) {
            JspFactory.setDefaultFactory(new JspFactoryImpl());
        }

        budoNettyServletServer.getServletContext() //
                .addServlet("JspServlet", BudoJspServlet.class) //
                .addMapping("*.jsp");
    }

    private void parseWebXml(DefaultBudoServletServer budoNettyServletServer) {
        InputStream xmlResource = budoNettyServletServer.getServletContext().getResourceAsStream("WEB-INF/web.xml");
        if (null == xmlResource) {
            log.warn("#40 web.xml not found");
            return;
        }

        XmlObject webXml = Xml.parse(xmlResource);
        XmlObject webApp = webXml.getChildNodeByName("web-app");

        BudoNettyServletWebXmlConfigParser webXmlConfigParser = new BudoNettyServletWebXmlConfigParser(budoNettyServletServer);
        webXmlConfigParser.setWebAppConf(webApp);
        webXmlConfigParser.parseWebXml();
    }

    private ResourceLoader resourceLoader() {
        try {
            File documentRoot = LauncherUtil.getDocumentRoot();
            log.info("#109 documentRoot=" + documentRoot);

            String rootPath = null;
            if (null != documentRoot) {
                rootPath = documentRoot.getCanonicalPath(); // 本地
            }

            if (null == rootPath) {
                File webapp = new File("webapp");
                if (webapp.exists() && webapp.isDirectory()) {
                    rootPath = webapp.getCanonicalPath(); // 服务器

                    log.info("#121 rootPath=" + rootPath);
                }
            }

            return new BudoFileResourceLoader(rootPath);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}